<?php
/*
 * MiniMe - a minimalistic OStatus complient microblogging tool
 * Copyright (C) 2010, Tuomas Koski - koski.tuomas@gmail.com
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * @author     Tuomas Koski <koski.tuomas@gmail.com>
 * @copyright  Tuomas Koski
 * @license    http://www.gnu.org/licenses/lgpl.txt
 */
abstract class Mm_Xml_Element_Builder_Abstract implements Mm_Xml_Element_Builder_Interface {
    
    protected $xpath;
    protected $domDoc;
    
    protected $childElements;
    
    protected $mandatoryChildElements = array();
    protected $optionalChildElements = array();
    
    protected $rawXML;
    
    protected $namespaces = array();
    
    protected function parseChildElementsFromRawXML() {
        $this->domDoc = new DOMDocument();
        if(!empty($this->rawXML) && $this->domDoc->loadXML($this->rawXML)) {
            
            $this->xpath = new DOMXPath($this->domDoc);
            
            $sxe = simplexml_import_dom($this->domDoc->documentElement);
            $this->namespaces = $sxe->getDocNamespaces(true);
            
            if(!isset($this->namespaces[""])) {
                // interesting situation.
            } else if($this->namespaces[""] == Mm_Atom::NS) {
                $this->xpath->registerNamespace(Mm_Atom::NS_PREFIX, Mm_Atom::NS);
            } else if($this->namespaces[""] == Mm_Xrd::NS) {
                $this->xpath->registerNamespace(Mm_Xrd::NS_PREFIX, Mm_Xrd::NS);
                // This is a hack, it will be fixed when dictionary of namespaces and prefixes is done
                $this->xpath->registerNamespace("hm", "http://host-meta.net/xrd/1.0");
            } else {
                //echo "namespace is '" . $this->namespaces[""] . "'\n";exit;
            }
            
            //var_dump($this->namespaces); 
            //echo $this->namespaces[""];exit;
            
            return $this->parseChildElementsFromDomDoc();
        }
        throw new Exception( get_class($this) . " - Invalid XML: " . $this->rawXML);
    }
    
    /**
     * @param DOMDocument $domDoc
     */
    protected function parseChildElementsFromDomDoc() {
        
        $childElements = array();
        
        foreach ($this->mandatoryChildElements as $info) {
            
//            echo "h:" . $info['xpath_query'] ;
//            var_dump($this->namespaces); 
//            echo $this->namespaces[""];exit;
            
            
            $elements = $this->xpath->query($info['xpath_query']);
            
            if($elements == null || $elements->length === 0) {
                throw new Exception( get_class($this) . " cannot be constructed. Mandatory elemenent for '" . $info['builder'] . "' could not be found using xpath query '" . $info['xpath_query'] . "'.");
            }
            
            try {
	            if(isset($info['can_have_multiple_items']) && $info['can_have_multiple_items'] == true) {
	                foreach ($elements as $elm) {
	                    $this->childElements[$info['key']][] = $this->buildElement($elm, $info);
	                }
	            } else {
	                $this->childElements[$info['key']] = $this->buildElement($elements->item(0), $info);
	            }
            } catch (Exception $e) {
                // TODO, fill me!
            }   
        }
        
        foreach ($this->optionalChildElements as $info) {
            $elements = $this->xpath->query($info['xpath_query']);
            
            if($elements == null || $elements->length == 0) {
               continue;
            }
            
            try {
	            if(isset($info['can_have_multiple_items']) && $info['can_have_multiple_items'] == true) {
	                
	                foreach ($elements as $elm) {
	                    $ret = $this->buildElement($elm, $info);
	                    $this->childElements[$info['key']][] = $this->buildElement($elm, $info);
	                }
	            } else {
	                $this->childElements[$info['key']] = $this->buildElement($elements->item(0), $info);
	            }
            } catch (Exception $e) {
                
            } 
        }     
    }
    
    protected function buildElement(DOMElement $elm, array $info) {
        if($info['type'] === 1) {
                
            $parser = new Mm_Xml_Element_Parser($elm);
            return new $info['builder']($parser->value, $parser->attributes);
            
        } else if ($info['type'] === 2) {

            foreach ($this->namespaces as $k => $v) {
                if(empty($k)) {
                    $elm->setAttribute("xmlns", $v);
                } else {
                    $elm->setAttributeNS('http://www.w3.org/2000/xmlns/', "xmlns:" . $k, $v);
                }
            }
            
            $builder = new $info['builder']($this->domDoc->saveXML($elm));
            $obj = $builder->build();
            //$obj->setNamespaces($this->namespaces);
            return $obj;
            
        }
        throw new Exception(get_class($this) . " - did not understand type '" . $info['type'] . "'. Panicing!");
    }
    
}